package org.zjvis.datascience.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zjvis.datascience.common.constant.NoticeConstant;
import org.zjvis.datascience.common.dto.notice.NoticeDTO;
import org.zjvis.datascience.common.dto.notice.NoticeQueryDTO;
import org.zjvis.datascience.common.dto.ProjectDTO;
import org.zjvis.datascience.common.dto.notice.NoticeSendDTO;
import org.zjvis.datascience.common.dto.user.UserConfigDTO;
import org.zjvis.datascience.common.enums.NoticeTypeEnum;
import org.zjvis.datascience.common.pool.BasePool;
import org.zjvis.datascience.common.util.DozerUtil;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.common.util.Page;
import org.zjvis.datascience.common.util.PageUtils;
import org.zjvis.datascience.common.util.RedisUtil;
import org.zjvis.datascience.common.vo.notice.NoticeQueryVO;
import org.zjvis.datascience.common.vo.notice.NoticeVO;
import org.zjvis.datascience.service.mapper.NoticeMapper;
import org.zjvis.datascience.service.socket.SocketIOService;

/**
 * @description Notice 用户提醒 Service
 * @date 2021-11-23
 */
@Service
public class NoticeService {
    private final static Logger logger = LoggerFactory.getLogger("NoticeService");

    @Autowired
    private BasePool threadPool;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private NoticeMapper noticeMapper;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private SocketIOService socketIOService;
    @Autowired
    private UserConfigService userConfigService;
    //TODO 暂时不需要，process方法中如果用到可放开注释
//    @Autowired @Lazy
//    private UserProjectService userProjectService;

    public void test() {
        Long userId = JwtUtil.getCurrentUserId();
        String message = "上传成功，开始解析";
        String key = "file_upload_"+userId;
        addTask(key,message);
        CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(3000L);

                addTask(key,"");
                Thread.sleep(3000L);

                addTask(key,"");
                Thread.sleep(3000L);

                addTask(key,"");

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, threadPool.getExecutor());
        System.out.println("结束");

    }

    public boolean addTask(String key, String value) {
        return redisUtil.lSet(key,value,600);
    }

    public List<Object> getTask(String key ) {
        return redisUtil.lGet(key,0,10);
    }

    /**
     * 获取消息列表
     * @param notice
     * @return
     */
    public Object query(NoticeVO notice) {
        NoticeDTO dto = notice.toNoticeDTO(JwtUtil.getCurrentUserId());

        PageHelper.startPage(notice.getPageNum(),notice.getPageSize()," gmt_modify desc ");
        List<NoticeQueryDTO> res = noticeMapper.query(dto);
        Set<Long> ids = new HashSet<>();

        List<NoticeQueryVO> nqvs = new ArrayList<>();
        for (NoticeQueryDTO nq:res) {
            NoticeQueryVO nv = DozerUtil.mapper(nq,NoticeQueryVO.class);

            if (StringUtils.isNotBlank(nq.getProcess())) {
                JSONObject jo = JSONObject.parseObject(nq.getProcess());
                if (jo.containsKey("projectId")) {
                    ids.add(jo.getLongValue("projectId"));
                    nv.setProjectId(jo.getLongValue("projectId"));
                }
            }
            nqvs.add(nv);
        }
        if (!ids.isEmpty()) {
            //获取项目名
            List<ProjectDTO> pds = projectService.queryByIds(ids);
            if (pds!=null&&!pds.isEmpty()) {
                for (NoticeQueryVO nqv:nqvs) {
                    for (ProjectDTO pd:pds) {
                        if (pd.getId().equals(nqv.getProjectId())){
                            nqv.setProjectName(pd.getName());
                            break;
                        }
                    }
                }
            }
        }

        Page page = PageUtils.getPageResult(PageInfo.of(res));
        page.setData(nqvs);

        return page;
    }

    /**
     * 读取未读消息
     * @param ids
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean process(Set<Long> ids) {
        //修改状态为已读
        int res = noticeMapper.batchUpdateStatus(JwtUtil.getCurrentUserId(),ids,1);
        return res>0?true:false;
    }

    /**
     * 删除消息
     * @param ids
     * @return
     */
    public boolean delete(Set<Long> ids) {
        int res = noticeMapper.delete(JwtUtil.getCurrentUserId(),ids);
        return res>0?true:false;
    }

    /**
     * 添加消息
     * @param notice
     */
    public void save(NoticeDTO notice) {
        noticeMapper.save(notice);
    }

    /**
     * 删除当前用户下的所有已读消息
     * @return
     * @param status
     */
    public boolean deleteAll(Integer status) {
        //TODO 注意，当前需求是只有已读才能被删除，传status是为后续需求改变做预留
        int res = noticeMapper.deleteAll(JwtUtil.getCurrentUserId(),1);
        return res>0?true:false;
    }

    /**
     *
     * @return
     */
    public boolean processAll() {
        int res = noticeMapper.batchUpdateStatus(JwtUtil.getCurrentUserId(),null,1);
        return res>0?true:false;
    }

    public void saveAndSendToUser(Long receiver,String title, String content, Integer type, Long creator) {
        saveAndSendToUser(receiver, title, content,null, type, creator);
    }

    public void saveAndSendToUser(Long receiver,String title, String content, String process, Integer type, Long creator) {
        if (receiver==null||receiver<1||StringUtils.isBlank(title)||StringUtils.isBlank(content)
            ||type==null||creator==null||creator<1) {
            return;
        }

        saveAndSendToUser(new HashSet<Long>(){{add(receiver);}}, title, content, process, type, creator);;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAndSendToUser(Set<Long> receivers,String title, String content, String process, Integer type, Long creator) {
        if (receivers==null||StringUtils.isBlank(title)||StringUtils.isBlank(content)
            ||type==null||creator==null||creator<1) {
            return;
        }

        //系统消息强制接收，非系统消息根据用户设置处理
        if (type != NoticeTypeEnum.system.getType()) {
            //根据用户设置筛选消息接收者
            Iterator<Long> iterator = receivers.iterator();
            while (iterator.hasNext()) {
                Long userId = iterator.next();
                UserConfigDTO config = userConfigService.query(userId);
                if (config==null) {
                    iterator.remove();
                    continue;
                }
                switch (config.getNoticeReceiveLevel()) {
                    case 2://与我相关
                        if (process==null||StringUtils.isBlank(process)) {
                            iterator.remove();
                            break;
                        }
                        JSONObject jo = JSONObject.parseObject(process);
                        if (!jo.containsKey("userId")||!userId.equals(jo.getLong("userId"))) {
                            iterator.remove();
                        }
                        break;
                    case 3://屏蔽消息（系统消息除外）
                        iterator.remove();
                        break;
                    case 1://所有消息
                    default:
                        break;
                }
            }
            if (receivers.isEmpty()) {
                return;
            }
        }
        List<NoticeDTO> notices = new ArrayList<>();
        for (Long receiver:receivers) {
            NoticeDTO notice = NoticeDTO.builder()
                .userId(receiver)
                .title(title)
                .content(content)
                .type(type)
                .process(process)
                .gmtCreator(creator)
                .gmtModifier(creator)
                .build();
            notices.add(notice);
        }

        saveAndSendToUser(notices);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAndSendToUser(List<NoticeDTO> notices) {
        if (notices==null) {
            return;
        }

        for (NoticeDTO notice:notices) {
            save(notice);
            //发送socket通知
            NoticeSendDTO data = DozerUtil.mapper(notice,NoticeSendDTO.class);
            socketIOService.sendToUser(notice.getUserId().toString(),NoticeConstant.SOCKET_EVENT_PROJECT_USER_ROLE,
                (JSONObject) JSON.toJSON(data));
        }
    }


}
